//calculator.cpp 实现calculator类
/*Designed by Zhenghua Ma, Department of Mechanical Engineering of THU, 2819538005@qq.com*/
#pragma once
#include"calculator.h"

template<typename T>
void Calculator<T>::centralCalculator(istream& stream) {
	int quit = 1;
	do {
		setColor(14, 0);//黄字黑底
		cout << "//********欢迎使用多功能矩阵计算器********//\n" << "//********Designed by Zhenghua Ma********//\n";
		cout << "这款矩阵计算器可以完成以下计算：\n一、矩阵基础运算：\n" << "    1.矩阵加减相乘    2.矩阵转置    3.矩阵数乘    4.合并增广矩阵\n" <<
			"    5.高斯消元        6.高斯消元展示过程          7.行简化阶梯型(RREF)化简\n" << "    8.RREF展示过程    9.计算矩阵的秩    10.QR分解\n" <<
			"二、针对方阵运算：\n" << "    1.求方阵行列式    2.求代数余子式    3.求伴随矩阵\n" << "    4.求逆矩阵        5.求逆并展示过程  6.方阵的迹\n" <<
			"    7.求特征值与特征向量    8.求奇异值    9.求谱范数\n" << "    10.求方阵的幂    11.可逆矩阵的LU分解\n" <<
			"注意：每次输入完请按下回车键，连续输入间用空格隔开\n";
		int order;
		while (1) {
			setColor(10, 0);//红字黄底
			cout << "下面请输入操作类型（矩阵基础运算-1，针对方阵运算-2，退出-0）：\n";
			stream >> order;
			if ((order == 0 || order == 1 || order == 2) && !stream.fail()) {
				break;
			}
			setColor(4, 6);//红字黄底
			cout << "输入有误，请重新输入操作类型！\n";
			stream.clear(); stream.ignore();//如果用户输入了如字符等非法数据，那么再次输入之前要清空输入流的异常情况和缓冲区
		}
		if (order == 0) {
			setColor(14, 0);//黄字黑底
			cout << "//********欢迎下次继续使用！********//\n";
			return;
		}
		int command1, command2;
		switch (order) {
		case 1: {
			while (1) {
				setColor(14, 0);//黄字黑底
				cout << "请输入具体需要执行的计算类型（1~10对应上方介绍）：\n";
				stream >> command1;
				if ((command1 >= 1 && command1 <= 10) && !stream.fail()) {
					break;
				}
				setColor(4, 6);//红字黄底
				cout << "输入有误，请重新输入计算类型！\n";
				stream.clear(); stream.ignore();
			}
			this->basicCalculator(stream, command1);
			break; }
		case 2: {
			while (1) {
				setColor(14, 0);//黄字黑底
				cout << "请输入具体需要执行的计算类型（1~11对应上方介绍）：\n";
				stream >> command2;
				if ((command2 >= 1 && command2 <= 11) && !stream.fail()) {
					break;
				}
				setColor(4, 6);//红字黄底
				cout << "输入有误，请重新输入计算类型：\n";
				stream.clear(); stream.ignore();
			}
			this->squareCalculator(stream, command2);
			break; }
		}
		while (1) {
			setColor(14, 0);//黄字黑底
			cout << "计算结束，是否需要继续计算呢？（继续-1，退出-0）\n";
			stream >> quit;
			if ((quit == 0 || quit == 1) && !stream.fail()) {
				break;
			}
			setColor(4, 6);//红字黄底
			cout << "输入有误，请重新输入是否退出！\n";
			stream.clear(); stream.ignore();
		}
		if (quit == 0)
			return;
	} while (quit == 1);
}

template<typename T>
void Calculator<T>::basicCalculator(istream& stream, int command) {
	Matrix<double> matrix[2];
	int col[2], row[2];
	while (1) {
		setColor(14, 0); cout << "初始化第一个矩阵，请输入行数和列数：\n";
		stream >> row[0] >> col[0];
		if (row[0] > 0 && col[0] > 0 && !stream.fail()) {
			break;
		}
		setColor(4, 6);//红字黄底
		cout << "输入的行数或列数不正确，请检查后再次输入！\n";
		stream.clear(); stream.ignore();
	}
	initializeMatrix(row[0], col[0], matrix[0], stream);
	cout << "这是第一个矩阵：\n";
	setColor(3, 0);//青字黑底
	matrix[0].printAll();
	if (command == 1 || command == 4) {
		while (1) {
			setColor(14, 0); cout << "初始化第二个矩阵，请输入行数和列数：\n";
			stream >> row[1] >> col[1];
			if (row[1] > 0 && col[1] > 0 && !stream.fail()) {
				break;
			}
			setColor(4, 6);//红字黄底
			cout << "输入的行数或列数不正确，请检查后再次输入！\n";
			stream.clear(); stream.ignore();
		}
		initializeMatrix(row[1], col[1], matrix[1], stream);
		cout << "这是第二个矩阵：\n";
		setColor(3, 0);//青字黑底
		matrix[1].printAll();
	}
	switch (command) {
	case 1: {
		int smallCommand;
		while (1) {
			setColor(14, 0); cout << "矩阵加法请输入1，减法请输入2，乘法请输入3：\n";
			stream >> smallCommand;
			if ((smallCommand == 1 || smallCommand == 2 || smallCommand == 3) && !stream.fail()) {
				break;
			}
			setColor(4, 6);//红字黄底
			cout << "输入有误，请重新输入操作类型！\n";
			stream.clear(); stream.ignore();
		}
		switch (smallCommand) {
		case 1:
			setColor(14, 0);//黄字黑底
			cout << "相加结果：\n";
			setColor(3, 0);//青字黑底
			(matrix[0] + matrix[1]).printAll();
			break;
		case 2:
			setColor(14, 0);//黄字黑底
			cout << "相减结果：\n";
			setColor(3, 0);//青字黑底
			(matrix[0] - matrix[1]).printAll();
			break;
		case 3:
			setColor(14, 0); cout << "相乘结果：\n";
			setColor(3, 0); (matrix[0] * matrix[1]).printAll();
			break;
		}
		break; }
	case 2: {
		setColor(14, 0); cout << "转置结果：\n";
		setColor(3, 0); (matrix[0].transpose()).printAll();
		break; }
	case 3: {
		double temp;
		while (1) {
			setColor(14, 0); cout << "请输入数乘的系数：\n";
			stream >> temp;
			if (!stream.fail())
				break;
			setColor(4, 6); cout << "输入的系数不正确，请检查后再次输入！\n";
		}
		cout << "数乘结果：\n";
		setColor(3, 0); (matrix[0] * temp).printAll();
		break; }
	case 4: {
		setColor(14, 0); cout << "增广矩阵：\n";
		setColor(3, 0); (matrix[0] | matrix[1]).printAll();
		break; }
	case 5: {
		setColor(14, 0); cout << "高斯消元结果：\n";
		setColor(3, 0); (matrix[0].GaussElimination()).printAll();
		break; }
	case 6: {
		setColor(3, 0); (matrix[0].showGaussElimination()).printAll();
		break; }
	case 7: {
		setColor(14, 0); cout << "行简化阶梯型为：\n";
		setColor(3, 0); (matrix[0].rref()).printAll();
		break; }
	case 8: {
		setColor(3, 0); (matrix[0].showRref());
		break; }
	case 9: {
		setColor(14, 0); cout << "矩阵的秩：\n";
		setColor(3, 0); cout << matrix[0].getRank() << endl;
		break; }
	case 10: {
		Matrix<double> Q, R;
		matrix[0].getQR(Q, R);
		setColor(14, 0); cout << "Q矩阵是：\n";
		setColor(3, 0); Q.printAll();
		setColor(14, 0); cout << "R矩阵是：\n";
		setColor(3, 0); R.printAll();
		break; }
	}
	return;
}

template<typename T>
void Calculator<T>::squareCalculator(istream& stream, int command) {
	Matrix<double> matrix;
	if (command == 8 || command == 9) {
		setColor(14, 0);
		cout << "求奇异值或谱范数支持一般矩阵（非方阵）进行哦！你可以输入任意矩阵！\n";
		int row, col;
		while (1) {
			setColor(14, 0); cout << "初始化矩阵，请输入矩阵的行数、列数：\n";
			stream >> row >> col;
			if (row > 0 && col > 0 && !stream.fail()) {
				break;
			}
			setColor(4, 6); cout << "输入的行数或列数不正确，请检查后再次输入！\n";
			stream.clear(); stream.ignore();
		}
		initializeMatrix(row, col, matrix, stream);
		cout << "这是您输入的矩阵：\n";
		setColor(3, 0); matrix.printAll();
	}
	else {
		int size;
		while (1) {
			setColor(14, 0); cout << "请输入方阵的阶数：\n";
			stream >> size;
			if (size > 0 && !stream.fail()) {
				break;
			}
			setColor(4, 6);//红字黄底
			cout << "输入的阶数不正确，请检查后再次输入！\n";
			stream.clear(); stream.ignore();
		}
		initializeMatrix(size, size, matrix, stream);
		cout << "这是您输入的方阵：\n";
		setColor(3, 0); matrix.printAll();
	}
	switch (command) {
	case 1: {
		SquareMatrix<double> square(matrix);
		setColor(14, 0); cout << "方阵的行列式：\n";
		setColor(3, 0); cout << square.getDeterminant() << endl;
		break; }
	case 2: {
		SquareMatrix<double> square(matrix);
		int row, col;
		while (1) {
			setColor(14, 0); cout << "请输入你需要获取代数余子式元素的位置（先行后列）：\n";
			stream >> row >> col;
			if (row > 0 && col > 0 && !stream.fail()) {
				break;
			}
			setColor(4, 6); cout << "输入的行数或列数不正确，请检查后再次输入！\n";
			stream.clear(); stream.ignore();
		}
		cout << "第(" << row << ',' << col << ")元的代数余子式是：\n";
		setColor(3, 0); cout << square.getAlgebraicCofactor(row, col) << endl;
		break; }
	case 3: {
		SquareMatrix<double> square(matrix);
		setColor(14, 0); cout << "伴随矩阵是：\n";
		setColor(3, 0); (square.getAdjointMatrix()).printAll();
		break; }
	case 4: {
		SquareMatrix<double> square(matrix);
		if (square.getDeterminant() == 0) {
			setColor(4, 6); cout << "该矩阵行列式为0，不可逆！\n";
			break;
		}
		setColor(14, 0);
		cout << "逆矩阵是：\n";
		setColor(3, 0); (square.getInverse()).printAll();
		break; }
	case 5: {
		SquareMatrix<double> square(matrix);
		setColor(3, 0); square.showInverseWithRref();
		break; }
	case 6: {
		SquareMatrix<double> square(matrix);
		setColor(14, 0); cout << "矩阵的迹：\n";
		setColor(3, 0); cout << square.getTrace() << endl;
		break; }
	case 7: {
		SquareMatrix<double> diag, Q, square(matrix);
		square.getEigenvalue_vector(diag, Q);
		setColor(14, 0); cout << "特征值是下面方阵的对角元：\n";
		setColor(3, 0); diag.printAll();
		setColor(14, 0); cout << "特征向量是下面方阵的每一列：\n";
		setColor(3, 0); Q.printAll();
		break; }
	case 8: {
		Matrix<double> temp(2, 2);//由于此时matrix不一定为方阵，直接使用matrix构造square会出错，因此使用临时的一个方阵调用对应函数
		SquareMatrix<double> square(temp);
		setColor(14, 0); cout << "奇异值是下面对角矩阵的对角元：\n";
		setColor(3, 0); (square.getSingularValue(matrix)).printAll();
		break; }
	case 9: {
		Matrix<double> temp(2, 2);
		SquareMatrix<double> square(temp);
		setColor(14, 0); cout << "谱范数是：\n";
		setColor(3, 0); cout << square.getNorm(matrix) << endl;
		break; }
	case 10: {
		int times;
		while (1) {
			setColor(14, 0); cout << "请输入所求的幂次（正整数）：\n";
			stream >> times;
			if (times > 0 && !stream.fail())
				break;
			setColor(4, 6); cout << "输入幂次不正确，请检查后再次输入！\n";
			stream.clear(); stream.ignore();
		}
		SquareMatrix<double> square(matrix);
		cout << "原方阵的" << times << "次幂是：\n";
		setColor(3, 0); (square.getPowerOfSquare(times)).printAll();
		break; }
	case 11: {
		SquareMatrix<double> square(matrix);
		Matrix<double> L, U;
		square.getLU(L, U);
		setColor(14, 0); cout << "下三角矩阵L是：\n";
		setColor(3, 0); L.printAll();
		setColor(14, 0); cout << "上三角矩阵U是：\n";
		setColor(3, 0); U.printAll();
		break; }
	}
	return;
}

template<typename T>
void Calculator<T>::setColor(int ForgC, int BackC) {
	WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);//进行移位与混合，让颜色0~15对应于system("color")
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
}//此段代码非我原创，而是参考了对应的资料

template<typename T>//初始化矩阵，可以充分检查输入的合法性，增强应对非法数据尤其是字符类型输入时的稳定性，5.30日新增
void Calculator<T>::initializeMatrix(int row, int col, Matrix<T>& matrix, istream& stream) {
	vector<double> tempVec;
	for (int i = 0; i < row; i++) {
		tempVec.clear();
		setColor(14, 0); cout << "请输入第" << i + 1 << "行元素：";
		for (int j = 0; j < col; j++) {
			double temp;
			while (1) {
				stream >> temp;
				if (!stream.fail()) {
					break;
				}
				setColor(4, 6);//红字黄底
				cout << "输入的元素不正确，请检查后再次输入！\n"; setColor(14, 0);
				stream.clear(); stream.ignore();
			}
			tempVec.push_back(temp);
		}
		matrix.addOneRowAtBottom(tempVec);
	}
}